# QSDK reset按键 ## 内核配置 ![image-20241022163758908](media/image-20241022163758908.png) ## dts配置 以`qcom-ipq6018-cp02-c1.dts`为例说明 - pinctrl配置 ``` &tlnm{ button_pins: button_pins { reset_button { pins = "gpio18"; function = "gpio"; drive-strength = <8>; bias-pull-down; }; }; }; ``` - reset按键配置 ``` &soc{ gpio_keys { compatible = "gpio-keys"; pinctrl-0 = <&button_pins>; pinctrl-names = "default"; reset { label = "reset"; linux,code = ; gpios = <&tlmm 18 GPIO_ACTIVE_LOW>; linux,input-type = <1>; debounce-interval = <60>; }; }; }; ``` 从上面的信息可以看出io使用的是gpio18,驱动使用的是`compatible = "gpio-keys";` ## 平台驱动 ```c static struct platform_driver gpio_keys_driver = { .probe = gpio_keys_probe, .remove = gpio_keys_remove, .driver = { .name = "gpio-keys", .owner = THIS_MODULE, .of_match_table = of_match_ptr(gpio_keys_of_match), }, }; ``` ```c static int __init gpio_button_init(void) { int ret; ret = platform_driver_register(&gpio_keys_driver); if (ret) return ret; return ret; } ``` ``` gpio_keys_probe gpio_keys_button_probe(pdev, &bdev, 0); // 启动工作队列和定时器 INIT_WORK(&bdata->work_irq, gpio_keys_gpio_work_func); setup_timer(&bdata->timer, gpio_keys_gpio_timer,); devm_request_irq // 申请中断 button_hotplug_event // 创建hotplug事件 ``` - `gpio_keys_gpio_work_fun`函数 ``` bdata->last_state = gpio_button_get_value(bdata); button_hotplug_event(bdata, bdata->b->type ?: EV_KEY, bdata->last_state); ``` - `gpio_keys_gpio_timer`函数 ``` struct gpio_keys_button_data *bdata = (struct gpio_keys_button_data *)_data; schedule_work(&bdata->work_irq); //启动 ``` - `button_hotplug_event`函数 ``` button_hotplug_create_event(button_map[btn].name, type, (seen - priv->seen) / HZ, value); ``` - `button_hotplug_create_event`函数 ``` static int button_hotplug_create_event(const char *name, unsigned int type, unsigned long seen, int pressed) { struct bh_event *event; BH_DBG("create event, name=%s, seen=%lu, pressed=%d\n", name, seen, pressed); event = kzalloc(sizeof(*event), GFP_KERNEL); if (!event) return -ENOMEM; event->name = name; event->type = type; event->seen = seen; event->action = pressed ? "pressed" : "released"; INIT_WORK(&event->work, (void *)(void *)button_hotplug_work); schedule_work(&event->work); return 0; } ``` - `button_hotplug_work`函数 ```c static void button_hotplug_work(struct work_struct *work) { struct bh_event *event = container_of(work, struct bh_event, work); int ret = 0; event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL); if (!event->skb) goto out_free_event; ret = bh_event_add_var(event, 0, "%s@", event->action); if (ret) goto out_free_skb; ret = button_hotplug_fill_event(event); if (ret) goto out_free_skb; NETLINK_CB(event->skb).dst_group = 1; broadcast_uevent(event->skb, 0, 1, GFP_KERNEL); //通过broadcast_uevent发到用户层。 out_free_skb: if (ret) { BH_ERR("work error %d\n", ret); kfree_skb(event->skb); } out_free_event: kfree(event); } ``` 驱动程序参见[reset按键和ipget按键在openwrt中的处理逻辑 - 轻轻的吻 - 博客园](https://www.cnblogs.com/yuanqiangfei/p/15252923.html) ## reset按键应用层处理 ``` #!/bin/sh [ "${ACTION}" = "released" ] || exit 0 . /lib/functions.sh logger "$BUTTON pressed for $SEEN seconds" if [ "$SEEN" -lt 1 ] then echo "REBOOT" > /dev/console sync reboot elif [ "$SEEN" -gt 5 ] then echo "FACTORY RESET" > /dev/console jffs2reset -y && reboot & fi return 0 ``` ## jffs2reset原理